#ifndef _UDP_SERVER_HPP
#define _UDP_SERVER_HPP

#include "Log.hpp"
#include <iostream>
#include <unordered_map>
#include <cstdio>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <queue>

#define SIZE 1024

class UdpServer
{ 
public:
    UdpServer(uint16_t port, std::string ip = "0.0.0.0")
        : _ip(ip),
          _port(port),
          _socketFd(-1)
    {
    }

    bool initServer()
    {
        // 新系统调用完成网络功能

        // 1. socket创建套接字 协议用IPv4 套接字类型用数据报套接字
        _socketFd = socket(AF_INET, SOCK_DGRAM, 0); // #define AF_INET PF_INET 二者相同
        if (_socketFd < 0)
        {
            logMsg(FATAL, "socket::%d:%s", errno, strerror(errno));
            exit(2); // 正规写法：规定每个退出码代表什么意思
        }

        // 2. bind绑定端口号 将一个套接字绑定到一个特定的地址和端口

        struct sockaddr_in svr_sockAddr;
        bzero(&svr_sockAddr, sizeof(svr_sockAddr));

        svr_sockAddr.sin_family = AF_INET;
        svr_sockAddr.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        svr_sockAddr.sin_port = htons(_port);

        // int bind(int __fd, const sockaddr *__addr, socklen_t __len)
        if (bind(_socketFd, (struct sockaddr *)&svr_sockAddr, sizeof(svr_sockAddr)) < 0)
        {
            logMsg(FATAL, "bind::%d:%s", errno, strerror(errno));
            exit(2);
        }
        logMsg(NORMAL, "init udp server done ... %s", strerror(errno));
        return true;
    }

    void Start()
    {
        char cmdBuf[SIZE];

        while (true)
        {
            // client_addr 纯输出型参数
            struct sockaddr_in client_addr;
            bzero(&client_addr, sizeof(client_addr));

            // clint_addrlen: 输入输出型参数
            socklen_t clint_addrlen = sizeof(client_addr); // unsigned int

            // 读取数据
            ssize_t bytes_read = recvfrom(_socketFd, cmdBuf, sizeof(cmdBuf) - 1, 0, (struct sockaddr *)&client_addr, &clint_addrlen);
            if (bytes_read == -1)
            {
                logMsg(FATAL, "recvfrom::%d:%s", errno, strerror(errno));
                exit(3);
            }

            // 谁 发送的 什么信息
            char partMsg[256];
            std::string cmdOutput;
            if (bytes_read > 0)
            {
                cmdBuf[bytes_read] = 0; // 数据当做字符串使用

                // 不允许客户端执行rm命令
                if (strcasestr(cmdBuf, "rm") != nullptr || strcasestr(cmdBuf, "rmdir") != nullptr)
                {
                    std::string err_msg = "大坏蛋！不准删除！";
                    std::cout << "client send:" << cmdBuf << ", but is blocked!" << std::endl;
                    sendto(_socketFd, err_msg.c_str(), err_msg.size(), 0, (struct sockaddr *)&client_addr, clint_addrlen);
                    continue;
                }

                FILE *fp = popen(cmdBuf, "r");
                if (nullptr == fp)
                {
                    //logMsg(ERROR, "popen::%d:%s", errno, strerror(errno));
                    continue;
                }

                //popen把cmdBuf的命令执行的结果存入到fp文件中
                while (fgets(partMsg, sizeof(partMsg), fp) != nullptr)
                {
                    cmdOutput += partMsg;
                }
                fclose(fp);

                sendto(_socketFd, cmdOutput.c_str(), cmdOutput.size(), 0, (struct sockaddr *)&client_addr, clint_addrlen);
            }
        }
    }
    ~UdpServer()
    {
        if (_socketFd >= 0)
            close(_socketFd);
    }

private:
    // ip和port
    std::string _ip;
    uint16_t _port;
    int _socketFd;
};

#endif